﻿
namespace Excel.UI {
    export interface WorkbookProps {
        workBook: Excel.WorkBook;
    }
    export interface WorkbookState {

    }
    export interface WorksheetProps {
        pFun: Function;
    }
    export interface ExcelMenuProps {
        style: any;
        pFun: Function;
    }
    export class AlignType {
        static Bottom = "bottom";
        static Top = "top";
        static Middle = "middle";
        static Left = "left";
        static Right = "right";
        static Center = "center";
    }

    export class BorderType {
        static None = "None";
        static Left = "BorderLeft";
        static Top = "BorderTop";
        static Right = "BorderRight";
        static Bottom = "BorderBottom";
        static All = "Border";
    }

    export class OperType {
        static Save = "Save";
        static OpenExcel = "OpenExcel";
        static ChangeSheet = "ChangeSheet";
        static MergeCells = "MergeCells";
        static UnMergeCells = "UnMergeCells";
        static Back = "Back";
        static Forward = "Forward";
        static Copy = "Copy";
        static Paste = "Paste";
        static PasteValue = "PasteValue";
        static Formula = "Formula";
        static Cancel = "Cancel";
        static Confirm = "Confirm";

        static AlignLeft = AlignType.Left;
        static AlignRight = AlignType.Right;
        static AlignCenter = AlignType.Center;
        static AlignTop = AlignType.Top;
        static AlignMiddle = AlignType.Middle;
        static AlignBottom = AlignType.Bottom;
        static BorderNone = BorderType.None;
        static BorderLeft = BorderType.Left;
        static BorderTop = BorderType.Top;
        static BorderRight = BorderType.Right;
        static BorderBottom = BorderType.Bottom;
        static BorderAll = BorderType.All;
    }

    export enum OperState {
        Do
        , Back
        , Forward
    }
    export interface RtData {
        Status: string;
        Message: any;
    }
    export interface OperStep {
        OperType: string;
        CopyData: Copy;
        OperData?: any;
        OperState: OperState;
    }
}
namespace Excel.UI {
    export class OperLog {
        backList: OperStep[];
        forwardList: OperStep[];
        constructor() {
            this.init();
        }
        init() {
            this.backList = [];
            this.forwardList = [];
        }
        add(operStep: OperStep) {
            if (operStep.OperState == OperState.Do) {
                this.backList.push(operStep);
                this.forwardList = [];
            }
        }
        back(): OperStep {
            let operStep = this.backList.pop();
            if (operStep) {
                operStep.OperState = OperState.Back;
                this.forwardList.push(operStep);
                return JSON.parse(JSON.stringify(operStep));
            }
            return null;
        }
        forward(): OperStep {
            let operStep = this.forwardList.pop();
            if (operStep) {
                operStep.OperState = OperState.Forward;
                this.backList.push(operStep);
                return JSON.parse(JSON.stringify(operStep));
            }
            return null;
        }
    }
    export class PubData {
        static workBook: Excel.WorkBook;
        static operLog: OperLog = new OperLog();

    }

    export class Workbook extends React.Component<WorkbookProps, WorkbookState>{
        index: number;
        constructor(props: WorkbookProps) {
            super(props);
            PubData.workBook = JSON.parse(JSON.stringify(this.props.workBook));
            this.index = 0;
        }
        myFun = (operStep: OperStep) => {
            switch (operStep.OperType) {
                case OperType.OpenExcel:
                    PubData.workBook = JSON.parse(operStep.OperData)
                    this.forceUpdate();
                    break;
            }
        }
        render() {
            return (
                React.createElement("div", { key: "wb_main" }, [
                    React.createElement(Worksheet, { key: "sheet" + (this.index++).toString(), pFun: this.myFun })
                ])
            );
        }
    }

    export class Worksheet extends React.Component<WorksheetProps, any>{
        index: number;
        activeMerge: Excel.Merge;
        beginCell: Excel.CellPoint;
        mouseDown: boolean;
        rowCount: number;
        colCount: number;
        cellData: any;
        width: number;
        constructor(props: WorksheetProps) {
            super(props);
            this.index = 0;
            this.initSheet(PubData.workBook.ActiveSheetIndex ? PubData.workBook.ActiveSheetIndex : 0);
            window.onmousedown = (e: MouseEvent) => {
                this.mouseDown = true;
            }
            window.onmouseup = (e: MouseEvent) => {
                this.mouseDown = false;
            }
        }
        initSheet = (sheetIndex: number) => {
            this.activeMerge = null;
            this.beginCell = null;
            this.mouseDown = false;
            PubData.workBook.ActiveSheetIndex = sheetIndex;
            this.colCount = this.getActiveSheet().ExpandedColumnCount;
            this.rowCount = this.getActiveSheet().ExpandedRowCount;
            this.cellData = null;
            this.width = 0;
        }
        getActiveSheet = (): Excel.WorkSheet => {
           return  PubData.workBook.WorkSheets[PubData.workBook.ActiveSheetIndex];
        }
        getCellDOM = (cell: Excel.CellPoint): React.Component<any, any> | Element => {
            let ref: string = "td_" + cell.RowNum.toString() + "_" + cell.CellNum.toString();
            return this.refs[ref];
        }

        deleteMerge = (merge: Excel.Merge): boolean => {
            let getMergeIndex = (merge: Excel.Merge): number => {
                var sheet = this.getActiveSheet();
                for (var i = 0; i < sheet.Merges.length; i++) {
                    var merge1 = sheet.Merges[i];
                    if (PubFun.jsonEqual(merge1.StartCell, merge.StartCell)) {
                        return i;
                    }
                }
                return -1;
            }
            var sheet = this.getActiveSheet();
            var i = getMergeIndex(merge);
            if (i >= 0) {
                sheet.Merges.splice(i, 1);
                return true;
            }
            return false;
        }
        mergeActive = (): Excel.Copy => {
            let merge: Excel.Merge = this.activeMerge;
            if (merge) {
                var sheet = this.getActiveSheet();
                if (merge.EndCell.RowNum - merge.StartCell.RowNum > 0 || merge.EndCell.CellNum - merge.StartCell.CellNum > 0) {
                    this.mergeCells(merge);
                    this.deleteMerge(merge);
                    sheet.Merges.push(merge);
                }
            }
            return { Merge: PubFun.jsonCopy(merge) };
        }
        unMergeActive = (): Copy=> {
            var merge = this.activeMerge;
            if (merge) {
                this.unMergeCells(merge);
                this.deleteMerge(merge);
            }
            return { Merge: PubFun.jsonCopy(merge) }
        }
        mergeCells = (merge: Merge) => {
            if (merge) {
                this.cancelActive();
                for (var r = merge.EndCell.RowNum; r >= merge.StartCell.RowNum; r--) {
                    for (var c = merge.EndCell.CellNum; c >= merge.StartCell.CellNum; c--) {
                        let cell: any = this.getCellDOM({ RowNum: r, CellNum: c });
                        if (r == merge.StartCell.RowNum && c == merge.StartCell.CellNum) {
                            cell.colSpan = merge.EndCell.CellNum - merge.StartCell.CellNum + 1;
                            cell.rowSpan = merge.EndCell.RowNum - merge.StartCell.RowNum + 1;
                        } else {
                            cell.style.display="none";
                        }
                    }
                }
               
            }
        }
        unMergeCells = (merge: Merge) => {
            if (merge) {
                this.cancelActive();
                for (var r = merge.StartCell.RowNum; r <= merge.EndCell.RowNum; r++) {
                    for (var c = merge.StartCell.CellNum; c <= merge.EndCell.CellNum; c++) {
                        let cell: any = this.getCellDOM({ RowNum: r, CellNum: c });
                        if (r == merge.StartCell.RowNum && c == merge.StartCell.CellNum) {
                            cell.colSpan = 1;
                            cell.rowSpan = 1;
                            this.beginCell = { RowNum: r, CellNum: c };
                        } else {
                            cell.style.display = "table-cell";
                        }
                    }
                }
            }
        }

        getMergeByCell = (cell: Excel.CellPoint): Merge => {
            let cell_1: any = this.getCellDOM(cell);
            return {
                StartCell: { RowNum: cell.RowNum, CellNum: cell.CellNum },
                EndCell: { RowNum: cell.RowNum + cell_1.rowSpan - 1, CellNum: cell.CellNum + cell_1.colSpan-1 }
            };
        }
        mergeOnFocus = (merge: Merge) => {
            if (merge) {
                this.cancelActive();
                for (var r = merge.StartCell.RowNum; r <= merge.EndCell.RowNum; r++) {
                    for (var c = merge.StartCell.CellNum; c <= merge.EndCell.CellNum; c++) {
                        let cell2: any = this.getCellDOM({ RowNum: 0, CellNum: c });//列头
                        cell2.className = "Cell HeadActiveCell USNone";
                        let cell3: any = this.getCellDOM({ RowNum: r, CellNum: 0 });//行头
                        cell3.className = "Cell HeadActiveCell USNone";
                    }
                }
                this.activeMerge = merge;
            }
        }

        setSelectStyle = (merge: Merge) => {
            if (merge) {
                let leftcell1: any = this.getCellDOM({ RowNum: merge.StartCell.RowNum, CellNum: 0 });
                let topcell1: any = this.getCellDOM({ RowNum: 0, CellNum: merge.StartCell.CellNum });
                let leftcell2: any = this.getCellDOM({ RowNum: merge.EndCell.RowNum, CellNum: 0 });
                let topcell2: any = this.getCellDOM({ RowNum: 0, CellNum: merge.EndCell.CellNum });
                let leftloc1: Location = PubFun.offset(leftcell1); 
                let toploc1: Location = PubFun.offset(topcell1); 
                let leftloc2: Location = PubFun.offset(leftcell2);
                let toploc2: Location = PubFun.offset(topcell2); 

                let loc1: Location = { Left: toploc1.Left - 1, Top: leftloc1.Top - 1 };
                let loc2: Location = { Left: toploc2.Left + topcell2.offsetWidth + 1, Top: leftloc2.Top + leftcell2.offsetHeight + 1 };

                let selectBox: any = this.refs["selectBox"];
                selectBox.style.display = "block";
                selectBox.style.left = loc1.Left.toString() + "px";
                selectBox.style.top = loc1.Top.toString() + "px";
                selectBox.style.width = (loc2.Left - loc1.Left).toString() + "px";
                selectBox.style.height = (loc2.Top - loc1.Top).toString() + "px";
            }
        }
        isActiveCell = (cell: Excel.CellPoint) => {
            return (this.activeMerge && cell.RowNum >= this.activeMerge.StartCell.RowNum && cell.RowNum <= this.activeMerge.EndCell.RowNum && cell.CellNum >= this.activeMerge.StartCell.CellNum && cell.CellNum <= this.activeMerge.EndCell.CellNum);
        }
        cancelActive = () => {
            var merge = this.activeMerge;
            if (merge) {
                for (var r = merge.StartCell.RowNum; r <= merge.EndCell.RowNum; r++) {
                    for (var c = merge.StartCell.CellNum; c <= merge.EndCell.CellNum; c++) {
                        let cell1: any = this.getCellDOM({ RowNum: r, CellNum: c });
                        if (cell1.contentEditable) cell1.contentEditable = false;
                        cell1.className = "Cell USNone";
                        let cell2: any = this.getCellDOM({ RowNum: 0, CellNum: c });//列头
                         cell2.className = "Cell HeadCell USNone";
                        let cell3: any = this.getCellDOM({ RowNum: r, CellNum: 0 });//行头
                        cell3.className = "Cell HeadCell USNone";
                    }
                }
            }
            let selectBox: any = this.refs["selectBox"];
            selectBox.style.display = "none";
            this.activeMerge = null;
            this.beginCell = null;
        }
        mouseDownCellHandle = (RowNum: number, CellNum: number) => {
            let _ = this;
            return (e: any) => {
                var sheet = _.getActiveSheet();
                let cell: Excel.CellPoint = { RowNum: RowNum, CellNum: CellNum };
                if (RowNum > 0 && CellNum > 0) {
                    _.cancelActive();
                    _.mergeOnFocus(_.getMergeByCell(cell))
                    sheet.ActiveCell = cell;
                } else {
                    
                    if (RowNum == 0 && CellNum == 0) {
                        _.cancelActive();
                        _.mergeOnFocus({ StartCell: { RowNum: 1, CellNum: 1 }, EndCell: { RowNum: _.rowCount, CellNum: _.colCount } });
                    } else if (RowNum == 0) {
                        if (e.nativeEvent.offsetX <= e.target.offsetWidth - 5) {
                            sheet.ActiveCell = cell;
                            _.cancelActive();
                            _.mergeOnFocus({ StartCell: { RowNum: 1, CellNum: CellNum }, EndCell: { RowNum: _.rowCount, CellNum: CellNum } });
                           
                        } else {
                            _.cellData = {
                                cell: cell,
                                cellSize: { width: e.target.offsetWidth, height: e.target.offsetHeight },
                                mousePoint: { x: e.clientX, y: e.clientY }
                            }
                        }
                    } else if (CellNum == 0) {
                        if (e.nativeEvent.offsetY <= e.target.offsetHeight - 5) {
                            _.cancelActive();
                            sheet.ActiveCell = cell;
                            _.mergeOnFocus({ StartCell: { RowNum: RowNum, CellNum: 1 }, EndCell: { RowNum: RowNum, CellNum: _.colCount } });
                        } else {
                            _.cellData = {
                                cell: cell,
                                cellSize: { width: e.target.offsetWidth, height: e.target.offsetHeight },
                                mousePoint: { x: e.clientX, y: e.clientY }
                            }
                        }
                    }
                }
                _.setSelectStyle(_.activeMerge);
            }
        }
        mouseUpCellHandle = (RowNum: number, CellNum: number) => {
            let _ = this;
            return (e: any) => {
                _.cellData = null;
            }
        }

        mouseMoveCellHandle = (RowNum: number, CellNum: number) => {
            let _ = this;
            let sheet = _.getActiveSheet();
            if (RowNum == 0 && CellNum > 0) {
                return function (e: any) {
                    if (e.nativeEvent.offsetX > e.target.offsetWidth - 5) e.target.style.cursor = 'col-resize';
                    else e.target.style.cursor = 'default';
                    if (_.mouseDown && _.cellData) {
                        let cell: any = _.getCellDOM(_.cellData.cell);
                        //调整列宽
                        let width = _.cellData.cellSize.width + e.clientX - _.cellData.mousePoint.x;
                        cell.style.width = width.toString() + "px";
                        cell.style.cursor = 'col-resize';
                        if (!sheet.Columns[CellNum]) sheet.Columns[CellNum] = {};
                        sheet.Columns[CellNum].Width = width;
                        if (_.activeMerge) {
                            _.mergeOnFocus(_.activeMerge);
                            _.setSelectStyle(_.activeMerge);
                        }
                    }
                }
            } else if (RowNum > 0 && CellNum == 0) {
                return function (e: any) {
                    if (e.nativeEvent.offsetY > e.target.offsetHeight - 5) e.target.style.cursor = 'row-resize';
                    else e.target.style.cursor = 'default';
                    if (_.mouseDown && _.cellData) {
                        let cell: any = _.getCellDOM(_.cellData.cell);
                        //调整行高
                        let height = _.cellData.cellSize.height + e.clientY - _.cellData.mousePoint.y;
                        cell.style.height = height.toString() + "px";
                        cell.style.cursor = 'row-resize';
                        if (!sheet.Rows[RowNum]) sheet.Rows[RowNum] = { Cells: {} };
                        sheet.Rows[RowNum].Height = height;
                        if (_.activeMerge) {
                            _.mergeOnFocus(_.activeMerge);
                            _.setSelectStyle(_.activeMerge);
                        }
                    }
                }
            }
            else return null;
        }
        mouseEnterCellHandle = (RowNum: number, CellNum: number) => {
            let _ = this;
            let judgeRectangleIntersect=(merge1: Merge, merge2: Merge): boolean =>{
                let zx: number = Math.abs(merge1.StartCell.CellNum + merge1.EndCell.CellNum - merge2.StartCell.CellNum - merge2.EndCell.CellNum);
                let x: number = Math.abs(merge1.StartCell.CellNum - merge1.EndCell.CellNum) + Math.abs(merge2.StartCell.CellNum - merge2.EndCell.CellNum);
                let zy: number = Math.abs(merge1.StartCell.RowNum + merge1.EndCell.RowNum - merge2.StartCell.RowNum - merge2.EndCell.RowNum);
                let y: number = Math.abs(merge1.StartCell.RowNum - merge1.EndCell.RowNum) + Math.abs(merge2.StartCell.RowNum - merge2.EndCell.RowNum);
                return (zx <= x && zy <= y);
            }
            let getMerge = (cell1: Excel.CellPoint, cell2: Excel.CellPoint): Merge => {
                let merge: Merge = { StartCell: { RowNum: cell1.RowNum, CellNum: cell1.CellNum }, EndCell: { RowNum: cell1.RowNum, CellNum: cell1.CellNum } };
                if (merge.StartCell.RowNum > cell2.RowNum) merge.StartCell.RowNum = cell2.RowNum;
                if (merge.StartCell.CellNum > cell2.CellNum) merge.StartCell.CellNum = cell2.CellNum;
                if (merge.EndCell.RowNum < cell2.RowNum) merge.EndCell.RowNum = cell2.RowNum;
                if (merge.EndCell.CellNum < cell2.CellNum) merge.EndCell.CellNum = cell2.CellNum;
                return merge;
            }
            return () => {
                var sheet = _.getActiveSheet();
                if (RowNum == 0 && CellNum == 0) return false;
                else if (RowNum > 0 && CellNum > 0) {
                    if (_.mouseDown && sheet.ActiveCell && sheet.ActiveCell.RowNum > 0 && sheet.ActiveCell.CellNum > 0) {
                        _.cancelActive();
                        if (_.beginCell == null) _.beginCell = sheet.ActiveCell;
                        let cell: CellPoint = { RowNum: RowNum, CellNum: CellNum };
                        let cell1: any = this.getCellDOM({ RowNum: RowNum, CellNum: CellNum });
                        if (_.beginCell.RowNum < cell.RowNum) cell.RowNum = RowNum + cell1.rowSpan - 1;
                        if (_.beginCell.CellNum < cell.CellNum) cell.CellNum = CellNum + cell1.colSpan - 1;
                        let merge1: Merge = getMerge(_.beginCell, cell);
                        for (let i = 0; i < sheet.Merges.length; i++) {
                            let merge2 = sheet.Merges[i];
                            if (judgeRectangleIntersect(merge1, merge2)) {
                                if (merge1.StartCell.RowNum > merge2.StartCell.RowNum) merge1.StartCell.RowNum = merge2.StartCell.RowNum;
                                if (merge1.StartCell.CellNum > merge2.StartCell.CellNum) merge1.StartCell.CellNum = merge2.StartCell.CellNum;
                                if (merge1.EndCell.RowNum < merge2.EndCell.RowNum) merge1.EndCell.RowNum = merge2.EndCell.RowNum;
                                if (merge1.EndCell.CellNum < merge2.EndCell.CellNum) merge1.EndCell.CellNum = merge2.EndCell.CellNum;
                            }
                        }
                        _.mergeOnFocus(merge1);
                        _.setSelectStyle(merge1);
                    }

                } else if (RowNum == 0) {
                    if (_.mouseDown && !_.cellData && sheet.ActiveCell && sheet.ActiveCell.RowNum == 0 && sheet.ActiveCell.CellNum > 0) {
                        let merge1: Merge = getMerge({ RowNum: 1, CellNum: sheet.ActiveCell.CellNum }, { RowNum: _.rowCount, CellNum: CellNum });
                        _.cancelActive();
                        _.mergeOnFocus(merge1);
                        _.setSelectStyle(merge1);
                    }
                } else if (CellNum == 0) {
                    if (_.mouseDown && !_.cellData && sheet.ActiveCell && sheet.ActiveCell.RowNum > 0 && sheet.ActiveCell.CellNum == 0) {
                        let merge1: Merge = getMerge({ RowNum: sheet.ActiveCell.RowNum, CellNum: 1 }, { RowNum: RowNum, CellNum: _.colCount });
                        _.cancelActive();
                        _.mergeOnFocus(merge1);
                        _.setSelectStyle(merge1);
                    }
                }

                return false;
            }
        }

        inputCellHandle = (RowNum: number, CellNum: number) => {
            let _ = this;
            return () => {
                var sheet = _.getActiveSheet();
                let cell: any = _.getCellDOM({ RowNum: RowNum, CellNum: CellNum });
                if (!sheet.Rows[RowNum]) sheet.Rows[RowNum] = { Cells: {} };
                if (!sheet.Rows[RowNum].Cells[CellNum]) sheet.Rows[RowNum].Cells[CellNum] = { Data: { Type: "String", Value: "" } }
                sheet.Rows[RowNum].Cells[CellNum].Data.Value = cell.innerText;
            }
        }

        doubleClickCellHandle = (RowNum: number, CellNum: number) => {
            let _ = this;
            if (RowNum > 0 && CellNum > 0) {
                return () => {
                    let cell: any = _.getCellDOM({ RowNum: RowNum, CellNum: CellNum });
                    cell.contentEditable = true;
                    cell.className = "Cell USText";
                    cell.focus();
                }
            } else return null;
        }
        getCellStyleID = (cell1: CellPoint) => {
            var sheet = this.getActiveSheet();
            if (sheet.Rows[cell1.RowNum] && sheet.Rows[cell1.RowNum].Cells[cell1.CellNum]) {
                return sheet.Rows[cell1.RowNum].Cells[cell1.CellNum].StyleID;
            }
            return null;
        }
        setCellStyleID = (cell1: CellPoint,styleID:string) => {
            var sheet = this.getActiveSheet();
            if (!sheet.Rows[cell1.RowNum]) sheet.Rows[cell1.RowNum] = { Cells: {}};
            if (!sheet.Rows[cell1.RowNum].Cells[cell1.CellNum]) sheet.Rows[cell1.RowNum].Cells[cell1.CellNum] = {};
            sheet.Rows[cell1.RowNum].Cells[cell1.CellNum].StyleID = styleID;
        }
       setCellStyle = (cell1: CellPoint) => {
            let checkBorder = (cell1: CellPoint, b: string) => {
                let styleID1 = this.getCellStyleID(cell1);
                let style2 = styleID1 ? PubData.workBook.Styles[styleID1] : null;
                if (style2 && style2.Borders && (style2.Borders.Border || style2.Borders[b])) return true;
                return false;
            }
            let getBorderStyle = (border: Excel.Border) => {
                return border.Weight.toString() + "px " + border.LineStyle + " " + border.Color + "";
            }
            var sheet = this.getActiveSheet();
          
            let cell: any = this.getCellDOM(cell1);
            cell.style.textAlign = null;
            cell.style.verticalAlign = null;
            cell.style.font = null;
            let cellT1 = { RowNum: cell1.RowNum - 1, CellNum: cell1.CellNum };
            let cellL1 = { RowNum: cell1.RowNum, CellNum: cell1.CellNum - 1 };
            if (!checkBorder(cellT1, "BorderBottom")) cell.style.borderTop = null;
            if (!checkBorder(cellL1, "BorderRight")) cell.style.borderLeft = null;
            cell.style.borderRight = null;
            cell.style.borderBottom = null;
            let styleID = this.getCellStyleID(cell1);
            if (styleID) {
                let style1 = PubData.workBook.Styles[styleID];
                if (style1) {
                    if (style1.Alignment) {
                        if (style1.Alignment.Horizontal) cell.style.textAlign = style1.Alignment.Horizontal;
                        if (style1.Alignment.Vertical) cell.style.verticalAlign = style1.Alignment.Vertical;
                    }
                    if (style1.Borders) {
                        if (style1.Borders.Border) {
                            if (!checkBorder(cellT1, "BorderBottom"))
                                cell.style.borderTop = getBorderStyle(style1.Borders.Border);
                            cell.style.borderBottom = getBorderStyle(style1.Borders.Border);

                            if (!checkBorder(cellL1, "BorderRight"))
                                cell.style.borderLeft = getBorderStyle(style1.Borders.Border);
                            cell.style.borderRight = getBorderStyle(style1.Borders.Border);
                        }
                        if (style1.Borders.BorderTop && !checkBorder(cellT1, "BorderBottom")) 
                            cell.style.borderTop = getBorderStyle(style1.Borders.BorderTop);
                        if (style1.Borders.BorderBottom)
                            cell.style.borderBottom = getBorderStyle(style1.Borders.BorderBottom);
                        if (style1.Borders.BorderLeft && !checkBorder(cellL1, "BorderRight"))
                            cell.style.borderLeft  = getBorderStyle(style1.Borders.BorderLeft);
                        if (style1.Borders.BorderRight)
                            cell.style.borderRight = getBorderStyle(style1.Borders.BorderRight);
                    }
                    if (style1.Font) {
                        if (style1.Font.FontName) cell.style.fontFamily = style1.Font.FontName;
                        if (style1.Font.Color) cell.style.color = style1.Font.Color;
                        if (style1.Font.Size) cell.style.fontSize = style1.Font.Size.toString() + "px";
                    }
                }
            }
        }

        copyMerge = (merge: Merge): Copy => {
            let copy: Copy = null;
            if (merge) {
                copy = {
                    Rows: {},
                    Merge: merge
                };
                var sheet = this.getActiveSheet();
                for (let r = merge.StartCell.RowNum; r <= merge.EndCell.RowNum; r++) {
                    if (sheet.Rows[r]) {
                        copy.Rows[r] = { Cells: {} };
                        for (let c = merge.StartCell.CellNum; c <= merge.EndCell.CellNum; c++) {
                            if (sheet.Rows[r].Cells[c]) {
                                copy.Rows[r].Cells[c] = PubFun.jsonCopy(sheet.Rows[r].Cells[c]);
                            }
                        }
                    }
                }
            }
            return copy;
        }
        
        pasteCopy = (copy: Copy) => {
            if (copy) {
                var sheet = this.getActiveSheet();
                for (let r = copy.Merge.StartCell.RowNum; r <= copy.Merge.EndCell.RowNum; r++) {
                    for (let c = copy.Merge.StartCell.CellNum; c <= copy.Merge.EndCell.CellNum; c++) {
                        if (!sheet.Rows[r]) sheet.Rows[r] = { Cells: {} };
                        if (copy.Rows[r]&&copy.Rows[r].Cells[c]) {
                            sheet.Rows[r].Cells[c] = PubFun.jsonCopy(copy.Rows[r].Cells[c]);
                        } else {
                            sheet.Rows[r].Cells[c] = null;
                        }
                        this.setCellStyle({ RowNum: r, CellNum: c });
                    }
                }
            }
        }
        
        addStyle = (style: Excel.Style): string => {
            let getStyleID = (style: Excel.Style): string => {
                for (let id in PubData.workBook.Styles) {
                    if (PubFun.jsonEqual( PubData.workBook.Styles[id] , style)) return id;
                }
                return null;
            }
            if (style) {
                let styleID1 = getStyleID(style);
                if (styleID1) return styleID1;
                else {
                    let styleID: number = 1;
                    while (PubData.workBook.Styles[styleID.toString()]) {
                        styleID++;
                    }
                    PubData.workBook.Styles[styleID.toString()] = PubFun.jsonCopy(style);
                    return styleID.toString();
                }
            }
            return null;
        }
        setActiveStyle = (style: Style): Copy => {
            if (this.activeMerge) {
                let copy: Copy = this.copyMerge(this.activeMerge);
                this.setMergeStyle(this.activeMerge, style);
                return copy;
            }
            return null;
        }
        setMergeStyle = (merge: Merge, style: Style) => {
            var sheet = this.getActiveSheet();
            for (let r = merge.StartCell.RowNum; r <= merge.EndCell.RowNum; r++) {
                for (let c = merge.StartCell.CellNum; c <= merge.EndCell.CellNum; c++) {
                    let cell: any = this.getCellDOM({ RowNum: r, CellNum: c });
                    let style1: Excel.Style;
                    let styleID = this.getCellStyleID({ RowNum: r, CellNum: c });
                    if (styleID) style1 = PubFun.jsonCopy(PubData.workBook.Styles[styleID]);
                    style1 = PubFun.jsonMerge(style1, style);
                    let styleID1: string = this.addStyle(style1);
                    this.setCellStyleID({ RowNum: r, CellNum: c }, styleID1);
                    this.setCellStyle({ RowNum: r, CellNum: c });
                }
            }
        }

        setActiveBorder = (borders: Borders): Copy => {
            if (this.activeMerge) {
                let copy: Copy = this.copyMerge(this.activeMerge);
                this.setMergeBorder(this.activeMerge, borders);
                return copy;
            }
            return null;
        }
        setMergeBorder = (merge: Merge, borders: Borders) => { //未完成
            var sheet = this.getActiveSheet();
            for (let r = merge.StartCell.RowNum; r <= merge.EndCell.RowNum; r++) {
                for (let c = merge.StartCell.CellNum; c <= merge.EndCell.CellNum; c++) {
                    let cell: any = this.getCellDOM({ RowNum: r, CellNum: c });
                    let style1: Excel.Style;
                    let styleID = this.getCellStyleID({ RowNum: r, CellNum: c });
                    if (styleID) style1 = PubFun.jsonCopy(PubData.workBook.Styles[styleID]);
                    style1.Borders = PubFun.jsonMerge(style1.Borders, borders);
                    let styleID1: string = this.addStyle(style1);
                    this.setCellStyleID({ RowNum: r, CellNum: c }, styleID1);
                    this.setCellStyle({ RowNum: r, CellNum: c });
                }
            }
        }
        loadStyles = () => {
            var sheet = this.getActiveSheet();
            for (let i = 0; i < sheet.Merges.length; i++) {
                this.mergeCells(sheet.Merges[i]);
            }
            for (let r in sheet.Rows) {
                let row = sheet.Rows[r];
                for (let c in row.Cells) {
                    this.setCellStyle({ RowNum: parseInt(r), CellNum: parseInt(c) });
                }
            }
            this.cancelActive();
            if (sheet.ActiveCell) {
                if (sheet.ActiveCell.RowNum > 0 && sheet.ActiveCell.CellNum > 0) {
                    this.activeMerge = this.getMergeByCell(sheet.ActiveCell);
                    this.mergeOnFocus(this.activeMerge);
                    this.setSelectStyle(this.activeMerge);
                }
            }
        }
        componentDidMount() {
            this.loadStyles();
        }
        myFun = (operStep: OperStep, callback: Function) => {
            let setStyle = (operStep: OperStep, style: Style)=>{
                if (operStep.OperState == OperState.Do) {
                    operStep.CopyData = this.setActiveStyle(style);
                    if (operStep.CopyData) PubData.operLog.add(operStep);
                } else if (operStep.OperState == OperState.Forward) {
                    this.setMergeStyle(operStep.CopyData.Merge, style);
                } else if (operStep.OperState == OperState.Back) {
                    this.pasteCopy(operStep.CopyData);
                }
                this.mergeOnFocus(operStep.CopyData.Merge);
                this.setSelectStyle(operStep.CopyData.Merge);
            }
            let style: Style;
            switch (operStep.OperType) {
                case OperType.ChangeSheet:
                    this.initSheet(operStep.OperData);
                    this.forceUpdate(() => {
                        this.loadStyles();
                    });
                    PubData.operLog.init();
                    break;
                case OperType.MergeCells:
                    if (operStep.OperState == OperState.Do) {
                        operStep.CopyData = this.mergeActive();
                        if (operStep.CopyData)PubData.operLog.add(operStep);
                    } else if (operStep.OperState == OperState.Forward) {
                        this.mergeCells(operStep.CopyData.Merge);
                    } else if (operStep.OperState == OperState.Back) {
                        this.unMergeCells(operStep.CopyData.Merge);
                    }
                    this.mergeOnFocus(operStep.CopyData.Merge);
                    this.setSelectStyle(operStep.CopyData.Merge);
                    break;
                case OperType.UnMergeCells:
                    if (operStep.OperState == OperState.Do) {
                        operStep.CopyData = this.unMergeActive();
                        if (operStep.CopyData)PubData.operLog.add(operStep);
                    } else if (operStep.OperState == OperState.Forward) {
                        this.unMergeCells(operStep.CopyData.Merge);
                    } else if (operStep.OperState == OperState.Back) {
                        this.mergeCells(operStep.CopyData.Merge);
                    }
                    this.mergeOnFocus(operStep.CopyData.Merge);
                    this.setSelectStyle(operStep.CopyData.Merge);
                    break;
                case OperType.AlignLeft:
                case OperType.AlignCenter:
                case OperType.AlignRight:
                case OperType.AlignTop:
                case OperType.AlignMiddle:
                case OperType.AlignBottom:
                     style = { Alignment: { Vertical: operStep.OperType } }
                    if (operStep.OperType == OperType.AlignLeft || operStep.OperType == OperType.AlignCenter || operStep.OperType == OperType.AlignRight) style = { Alignment: { Horizontal: operStep.OperType } }
                    setStyle(operStep, style);
                    break;
                case OperType.BorderNone:
                case OperType.BorderTop:
                case OperType.BorderBottom:
                case OperType.BorderLeft:
                case OperType.BorderRight:
                case OperType.BorderAll:
                    style = { Borders: {} }
                    if (operStep.OperType == OperType.BorderNone) style.Borders = null;//borders["Border"] = { Weight: 1, LineStyle: "solid", Color: "rgb(220, 220, 220)" };
                    else style.Borders[operStep.OperType] = { Weight: 1, LineStyle: "solid", Color: "#000000" };
                    setStyle(operStep, style);
                    break;
                default:
                    this.props.pFun(operStep);
                    break;
            }
            callback && callback();
        }
        createRows = () => {
            let sheet = this.getActiveSheet();
            let createCell = (RowNum: number, CellNum: number) => {
                let ref: string = "td_" + RowNum.toString() + "_" + CellNum.toString();
                let style: any = {};
                let className = "Cell USNone";
                let value: string = "";

                if (RowNum == 0) {//列头
                    if (CellNum > 0) value = Excel.PubFun.convert26(CellNum);
                    className = "Cell HeadCell USNone";
                    let width: number = sheet.DefaultColumnWidth;
                    if (CellNum == 0) width = 72;
                    if (CellNum > 0 && sheet.Columns && sheet.Columns[CellNum] && sheet.Columns[CellNum].Width) 
                        width = sheet.Columns[CellNum].Width;
                    style = { width: width };
                    this.width += width;
                } else {
                    if (CellNum == 0) {//行头
                        value = RowNum.toString();
                        className = "Cell HeadCell USNone";
                        let height: number = sheet.DefaultRowHeight;
                        if (sheet.Rows[RowNum] && sheet.Rows[RowNum].Height) height = sheet.Rows[RowNum].Height;
                        style = { height: height };
                    } else {
                        if (sheet.Rows[RowNum] && sheet.Rows[RowNum].Cells && sheet.Rows[RowNum].Cells[CellNum]) {
                            value = sheet.Rows[RowNum].Cells[CellNum].Data.Value;
                        }
                    }
                }
                return React.createElement("td", { key: "td_" + CellNum.toString(), ref: ref, style: style, className: className, onInput: this.inputCellHandle(RowNum, CellNum), onDoubleClick: this.doubleClickCellHandle(RowNum, CellNum), onMouseDown: this.mouseDownCellHandle(RowNum, CellNum), onMouseUp: this.mouseUpCellHandle(RowNum, CellNum), onMouseEnter: this.mouseEnterCellHandle(RowNum, CellNum), onMouseMove: this.mouseMoveCellHandle(RowNum, CellNum) }, value);
            }
            let rows: React.ReactElement<any>[] = [];
            this.width = 0;
            for (let r = 0; r <= this.rowCount; r++) {
                let cells: React.ReactElement<any>[] = [];
                for (let c = 0; c <= this.colCount; c++) {
                    cells.push(createCell(r, c));
                }
                let key: string = "tr_" + r.toString();
                rows.push(React.createElement("tr" as any, { key: key, ref: key }, cells));
            }
            return rows;
        }
        render() {
            let rows: React.ReactElement<any>[] = this.createRows();
            return (
                React.createElement("div" as any, { key: 'worksheet', style: { position: "relative", width: "99%", height: "99%", overflow: "auto" } }, [
                    React.createElement(ExcelMenu, { key: "excelMenu", pFun: this.myFun, style: { position: "relative" } }),

                    React.createElement("div" as any, { key: "excelEdit", style: { width: "100%" } }, [
                        React.createElement("div" as any, { key: "div0", style: { float: "left", height: 30 } }, [
                            React.createElement(antd.Input, { key: "ip1", style: { width: 100 } })
                        ]),
                        React.createElement("div" as any, { key: "div1", style: { float: "left", height: 30 } }, [
                            PubFun.getButton("cancel", "anticon anticon-close"),
                            PubFun.getButton("confirm", "anticon anticon-check"),
                            PubFun.getButton("formula", "iconfont icon-hanshu"),
                        ]),
                        React.createElement("div" as any, { key: "div2", style: { float: "left", height: 30 } }, [
                            React.createElement(antd.Input, { key: "ip1", style: { width: 500 }, addonAfter: React.createElement("i" as any, { key: "icon", className: "anticon anticon-down", style: { fontSize: 16 } }) })
                        ]),
                        React.createElement("div" as any, { key: "clear", style: { clear: "both" } }),
                    ]),
                    React.createElement("table" as any, { key: "table" + (this.index++).toString(), style: { borderSpacing: 0, tableLayout: "fixed", width: this.width } }, rows),
                    React.createElement("div" as any, { key: 'selectBox', ref: "selectBox", style: { position: "absolute", display: "none", border: "2px solid #3366CC", pointerEvents: "none" } })
                ])
            );
        }
    }


    export class ExcelMenu extends React.Component<ExcelMenuProps, any>{
        constructor(props: ExcelMenuProps) {
            super(props);
        }
        getSelectOpt = () => {
  
            let opts: React.ReactElement<any>[] = [];
            for (let i = 0; i < PubData.workBook.WorkSheets.length; i++) {
                let name = PubData.workBook.WorkSheets[i].SheetName;
                opts.push(React.createElement(antd.Select.Option, { key: "opt_" + i.toString(), value: i.toString() }, name));
            }
            return opts;
        }
        menuHandle = (operType: string) => {
            switch (operType) {
                case OperType.ChangeSheet:
                    return (e: any) => {
                        this.props.pFun({ OperType: operType, OperState: OperState.Do, OperData: e }, () => {
                            this.forceUpdate();
                        });
                    }
                case OperType.OpenExcel:
                    return (info: any) => {
                        if (info.file.status === 'done') {
                            if (info.file.response.Status == "success") {
                                let fileName: string = info.file.response.Message;
                                Excel.PubFun.server("../Server.ashx",{ "FunctionName": "GetExcel", "FileName": fileName }, (rt: RtData) => {
                                    if (rt.Status == "success") {
                                        this.props.pFun({ OperType: operType, OperState: OperState.Do, OperData: rt.Message }, () => {
                                            this.forceUpdate();
                                        });
                                    } else {
                                        antd.message.error(rt.Message);
                                    }
                                });
                            }
                        }
                        this.forceUpdate();
                    }
                case OperType.Back:
                    return (e: any) => {
                        let operStep = PubData.operLog.back();
                        if (operStep) this.props.pFun(operStep, () => {
                            this.forceUpdate();
                        });
                    }
                case OperType.Forward:
                    return (e: any) => {
                        let operStep = PubData.operLog.forward();
                        if (operStep) this.props.pFun(operStep, ()=> {
                            this.forceUpdate();
                        });
                       
                    }
                default:
                    return () => {
                        this.props.pFun({ OperType: operType, OperState: OperState.Do }, () => {
                            this.forceUpdate();
                        });

                    }
            }
        }
    

        handleMenuClick = (e:any) => {
            let handle = this.menuHandle(e.key);
            handle(e);
        }

        render() {
            let overlay1: React.ReactElement<any> = React.createElement(antd.Menu, { onClick: this.handleMenuClick, style: { color: "#000", verticalAlign: "middle" } }, [
                PubFun.getMenuItem(OperType.BorderNone, "iconfont icon-border", "无边框"),
                PubFun.getMenuItem(OperType.BorderAll, "iconfont icon-biankuangquan", "全边框"),
                PubFun.getMenuItem(OperType.BorderTop, "iconfont icon-biankuanghengshang", "上边框"),
                PubFun.getMenuItem(OperType.BorderBottom, "iconfont icon-biankuanghengxia", "下边框"),
                PubFun.getMenuItem(OperType.BorderLeft, "iconfont icon-biankuangshuzuo", "左边框"),
                PubFun.getMenuItem(OperType.BorderRight, "iconfont icon-biankuangshuyou", "右边框"),
            ]);
            let overlay2: React.ReactElement<any> = React.createElement(antd.Menu, { onClick: this.handleMenuClick, style: { color: "#000", verticalAlign: "middle" } }, [
                PubFun.getMenuItem(AlignType.Center, "iconfont icon-chuizhijuzhong", "居中"),
                PubFun.getMenuItem(AlignType.Middle, "iconfont icon-shuipingjuzhong", "垂直居中"),
                PubFun.getMenuItem(AlignType.Left, "iconfont icon-zuoduiqi1", "左对齐"),
                PubFun.getMenuItem(AlignType.Right, "iconfont icon-youduiqi1", "右对齐"),
                PubFun.getMenuItem(AlignType.Top, "iconfont icon-shangduiqi", "顶端对齐"),
                PubFun.getMenuItem(AlignType.Bottom, "iconfont icon-xiaduiqi", "下对齐"),
            ]);
            let overlay3: React.ReactElement<any> = React.createElement(antd.Menu, { onClick: this.handleMenuClick, style: { color: "#000", verticalAlign: "middle" } }, [
                PubFun.getMenuItem(OperType.MergeCells, "iconfont icon-hebingdanyuange", "合并单元格"),
                PubFun.getMenuItem(OperType.UnMergeCells, "iconfont icon-quxiaohebingdanyuange", "取消合并"),
                PubFun.getMenuItem(OperType.Copy, "iconfont icon-fuzhi", "复制"),
                PubFun.getMenuItem(OperType.Paste, "iconfont icon-niantie", "粘贴"),
                PubFun.getMenuItem(OperType.PasteValue, "iconfont icon-niantie", "粘贴文本"),
            ]);
            return (
                React.createElement("div" as any, { style: this.props.style }, [
                    React.createElement("div" as any, { key: "excelMenu", style: {width:"100%"} }, [
                        React.createElement("div" as any, { key: "div0", style: { float: "left", height: 30 } }, [
                            React.createElement(antd.Upload, { key: "u1", action: "../Upload.ashx", showUploadList: false, onChange: this.menuHandle(OperType.OpenExcel) }, [
                                PubFun.getButton("bt_open", "anticon anticon-folder-open"),
                            ]),
                            PubFun.getButton("bt_save","anticon anticon-save", this.menuHandle(OperType.Save)),
                            PubFun.getButton("bt_houtui","iconfont icon-houtui", this.menuHandle(OperType.Back), PubData.operLog.backList.length == 0),
                            PubFun.getButton("bt_qianjin","iconfont icon-qianjin", this.menuHandle(OperType.Forward), PubData.operLog.forwardList.length == 0),
                        ]),
                        React.createElement("div" as any, { key: "div1", style: { float: "left", height: 30 } }, [
                            React.createElement(antd.Dropdown.Button, { key: "dbt", overlay: overlay3 }, "操作")
                        ]),
                        React.createElement("div" as any, { key: "div2", style: { float: "left", height: 30 } }, [
                            React.createElement(antd.Dropdown.Button, { key: "dbt", overlay: overlay1 }, "边框")
                        ]),
                        React.createElement("div" as any, { key: "div3", style: { float: "left", height: 30 } }, [
                            React.createElement(antd.Dropdown.Button, { key: "dbt", overlay: overlay2 }, "对齐")
                        ]),
                        React.createElement("div" as any, { key: "div4", style: { float: "left", height: 30 } }, [
                            React.createElement(antd.Select, { key: "s1", defaultValue: PubData.workBook.ActiveSheetIndex.toString(), style: { width: 100 }, onChange: this.menuHandle(OperType.ChangeSheet) }, this.getSelectOpt()),
                        ]),
                        React.createElement("div" as any, { key: "clear", style: { clear: "both" } }),
                    ])
                   
                ])
            );
        }
    }
}
